package com.yejiali.backend.ws;

import com.yejiali.backend.common.constant.SystemConstant;
import com.yejiali.backend.entity.SendMessage;
import com.yejiali.backend.service.MessagesService;
import com.yejiali.backend.util.JsonUtil;
import com.yejiali.backend.util.MessageUtil;
import com.yejiali.backend.util.RedisUtil;
import com.yejiali.backend.util.SpringContextUtils;
import jakarta.annotation.PostConstruct;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * @Author:yejiali
 * @Date:2025/8/19-08-19-10:02
 * @Decsription:com.yejiali.backend.ws
 * @Version:1.0
 */
@Component
@ServerEndpoint(value = "/ws/{userId}")
@Slf4j
public class WebSocketServer {


    /**
     * 与某个客户端的连接对话，需要通过它来给客户端发送消息
     */
    private Session session;

    public Session getSession(){
        return session;
    }

    /**
     * 标识当前连接客户端的用户名
     */
    private String userId;

    /**
     * 线程安全的hashmap，存每个客户端的连接，key 即是 userId, value这里是类名，
     * 所有Endpoint实例使用同一个map集合
     */
    public static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    public static ConcurrentHashMap<String, WebSocketServer> getWebSocketMap() {
        return webSocketMap;
    }


    private static MessagesService messagesService;
    private static RedisUtil redisUtil;

    @PostConstruct
    public void init(){
        messagesService = SpringContextUtils.getBean(MessagesService.class);
        redisUtil = SpringContextUtils.getBean(RedisUtil.class);
    }
    //
    private static final AtomicInteger onlineCount = new AtomicInteger(0);
    public static int getOnlineCount() {
        return onlineCount.get();
    }
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId){
        this.session = session;
        this.userId=userId;
        try{
            if(webSocketMap.containsKey(userId)){
                // 关闭旧的连接
                webSocketMap.get(userId).session.close();
                // 从map中移除旧的连接
                webSocketMap.remove(userId);
                webSocketMap.put(userId,this);
            }else {
                webSocketMap.put(userId, this);
                onlineCount.incrementAndGet();
            }
            log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
        }catch (Exception e) {
            log.error("用户连接失败", e);
        }
    }
    /**
     * 收到客户端消息后调用的方法
     * 浏览器发送消息格式{"toUserId":"","message":""}
     * 服务器发送消息格式{"fromUserId":"","message":"","type":"private"}
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        if(StringUtils.hasText(message)){
            //解析浏览器发送的报文
            SendMessage sendMessage = JsonUtil.parse(message, SendMessage.class);
            //拿到要发消息的人ID
            String toUserId = sendMessage.getToUserId();
            //拿消息的内容
            String messageContent = sendMessage.getMessage();
            //查看对方是否在线
            if(webSocketMap.containsKey(toUserId)){
                //获取接收方的session对象
                WebSocketServer webSocketServer = webSocketMap.get(toUserId);
                //置为私信
                String messageStr = MessageUtil.getMessage(SystemConstant.SEND_CHAT_MESSAGE, userId, messageContent);
                //推送消息
                webSocketServer.sendMessage(messageStr,webSocketServer.getSession());
                //保存消息
                messagesService.saveMessage(Long.parseLong(toUserId), Long.parseLong(userId), messageContent);
                log.info("用户消息:"+userId+",报文:"+messageStr);
            }else {
                // 储存离线消息
                messagesService.saveMessage(Long.parseLong(toUserId), Long.parseLong(userId), messageContent);
            }
            //暂时记录为未读
            redisUtil.hincr("unreadCount:"+toUserId, userId, 1);
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            //从set中删除
            onlineCount.decrementAndGet();
        }
        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }
    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
//        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 服务器主动推送(私信)
     */
    public static void sendMessage(String message,Session session) {
        try{
            session.getBasicRemote().sendText(message);
        }catch (Exception e){
            log.error("发送消息失败",e);
        }
    }

    /**
     * 服务器主动推送(广播)
     */
    public static void sendAllMessage(String message) {
        try{
        ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
        for (String userId : userIds) {
            WebSocketServer webSocketServer = webSocketMap.get(userId);
            if(userIds.contains(userId)){
                webSocketServer.session.getBasicRemote().sendText(message);
            }
        }
        }catch (Exception e){
            log.error("发送消息失败",e);
        }
    }

    /**
     * 服务器主动推送(多人@)
     * 多人@
     */
    public static void sendUsersMessage(String message, List<String> atUserIds) {
        try{
            ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
            for (String userId : atUserIds) {
                if(userIds.contains(userId)){
                    webSocketMap.get(userId).session.getBasicRemote().sendText(message);
                }
            }
        }catch (Exception e){
            log.error("发送消息失败",e);
        }
    }



}
